package org.jvm;

import org.jvm.classpath.*;
import org.jvm.instruction.base.InstructionUtil;
import org.jvm.rtda.Object;
import org.jvm.rtda.heap.Klass;
import org.jvm.rtda.heap.classLoader.KlassLoaderRegister;
import org.jvm.rtda.heap.classmember.Method;
import org.jvm.rtda.heap.stringpool.StringPool;
import org.jvm.rtda.thread.Thread;
import org.jvm.util.JavaCallUtil;

import java.util.Optional;


/**
 * author : 海燕
 * date : 2022/12/31
 * desc :Java Vitual Machine by Java
 */
public class JVM {

    public static boolean log = false;

    public static Cmd cmd;

    private Thread mainThread;

    /**
     * jre中lib路径
     */
    private BootClassPath classPath;

    public JVM(Cmd cmd) {
        JVM.cmd = cmd;
        classPath = new BootClassPath(JVM.cmd.getXjreOption(), JVM.cmd.getCpOption());
        //初始化根类加载器
        KlassLoaderRegister.initBootKlassLoader(classPath);
        this.mainThread = new Thread("main");
    }

    public static void main(String[] args) {
        Cmd cmd = new Cmd(args);
        if (cmd.getVersionFlag()) {
            System.out.println("version 0.0.1");
        } else if (cmd.getHelpFlag()) {
            System.out.println("Usage: [-options] class [args...]\n");
        } else {
            new JVM(cmd).startJVM();
        }
    }

    private void startJVM() {
        initVM();
        initClassLoader();
        execMain();
    }

    /**
     * 初始化类加载器
     */
    private void initClassLoader() {
        //初始化系统类加载器
        Klass classLoaderKlass = KlassLoaderRegister.getBootKlassLoader().loadKlass("java/lang/ClassLoader");
        Method getSystemClassLoaderMethod = classLoaderKlass.getStaticMethod("getSystemClassLoader", "()Ljava/lang/ClassLoader;");
        Object appClassLoader = (Object) JavaCallUtil.javaCall(mainThread, getSystemClassLoaderMethod, null);
        //初始化拓展类加载器
        Object extClassLoader = appClassLoader.getRefVar("parent", "Ljava/lang/ClassLoader;");
        KlassLoaderRegister.initExtAndAppClassLoader(extClassLoader, appClassLoader);
    }

    /**
     * 初始化sun公司的VM类，为支持标准输出做准备
     */
    private void initVM() {
        InstructionUtil.initClass(this.mainThread, KlassLoaderRegister.getBootKlassLoader().loadKlass("sun/misc/VM"));
    }

    /**
     * 执行main方法
     */
    private void execMain() {
        try {
            //加载启动类
            String className = JVM.cmd.getClassName().replace(".", "/");
            Klass mainClass = KlassLoaderRegister.loadKlass(className, mainThread);
            //提取main方法
            Method mainMethod = mainClass.getMainMethod();
            if (mainMethod == null) {
                throw new RuntimeException("main method no found");
            }
            //提取main方法入参，即String[] args
            Object mainParamStringArray = getMainParamStringArray();
            //发起javaCall执行main方法
            JavaCallUtil.javaCall(mainThread, mainMethod, null, mainParamStringArray);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Object getMainParamStringArray() {
        String[] args = Optional.ofNullable(JVM.cmd.getArgs()).orElse(new String[0]);
        Klass stringArrayClass = KlassLoaderRegister.getBootKlassLoader().loadKlass("[Ljava/lang/String;");
        Object stringArrayObject = stringArrayClass.newArray(args.length);
        for (int i = 0; i < stringArrayObject.refs().length; i++) {
            Object jString = StringPool.jString(args[i]);
            stringArrayObject.refs()[i] = jString;
        }
        return stringArrayObject;
    }
}
